package com.zjx.activiti.controller;


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zjx.activiti.common.Result;
import com.zjx.activiti.service.ProcessInfoService;
import com.zjx.activiti.vo.ReProcdef;
import com.zjx.activiti.util.ToWeb;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;

/**
 * 流程控制接口
 *
 * @Auther: zhaojx
 * @Date: 2021/8/25 15:04
 */
@Slf4j
@RestController
@RequestMapping("prof")
public class ActivitiController {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private ProcessInfoService processInfoService;

    @Autowired
    private IdentityService identityService;

    /**
     * 启动一个流程
     *
     * @auther: zhaojx
     * @date: 2021/8/25 15:24
     */
    @GetMapping("start")
    public Object start(@RequestParam("key") String key,
                        @RequestParam(value = "businessKey", required = false) String businessKey) {
        //设置流程发起人
        identityService.setAuthenticatedUserId("tom");
        ProcessInstance processInstance = null;
        //如果业务key不为空则传入（此key用于关联业务表）
        if (StringUtils.hasLength(businessKey)) {
            processInstance = runtimeService.startProcessInstanceByKey(key, businessKey);
        } else {
            processInstance = runtimeService.startProcessInstanceByKey(key);
        }
        log.info("启动一个流程实例，id为：{},businessKey:{}", processInstance.getId(), processInstance.getBusinessKey());
        return ToWeb.buildResult().refresh();
    }

    /**
     * 启动一个流程(包含流程变量)
     * <p>
     * 参数：
     * key:  流程定义KEY
     * <p>
     * bussId：  业务对象序号
     * bussName：业务对象名称
     * bussType：业务对象类型
     * startUserId: 发起人id
     * startUnitId: 发起人单位id
     *
     * @auther: zhaojx
     * @date: 2021/8/25 15:24
     */
    @PostMapping("run/{key}")
    public Result<String> run(@PathVariable String key,
                              @RequestBody Map<String, Object> variables,
                              @RequestParam(value = "businessKey", required = false) String businessKey) {
        //设置流程发起人
        identityService.setAuthenticatedUserId("tom");
        ProcessInstance processInstance = null;
        //如果业务key不为空则传入（此key用于关联业务表）
        if (StringUtils.hasLength(businessKey)) {
            processInstance = runtimeService.startProcessInstanceByKey(key, businessKey, variables);
        } else {
            processInstance = runtimeService.startProcessInstanceByKey(key, variables);
        }
        log.info("启动一个流程实例，id为：{},businessKey:{}", processInstance.getId(), processInstance.getBusinessKey());
        return new Result<>(processInstance.getId());
    }


    /**
     * 查询流程定义列表
     *
     * @param rowSize 一页数据大小
     * @param page    当前页码
     * @return
     */
    @GetMapping
    public Object getList(@RequestParam(value = "rowSize", defaultValue = "1000", required = false) Integer rowSize,
                          @RequestParam(value = "page", defaultValue = "1", required = false) Integer page) {
        List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery()
                .listPage(rowSize * (page - 1), rowSize);
        long count = repositoryService.createProcessDefinitionQuery().count();
        List<ReProcdef> list = new ArrayList<>();
        for (ProcessDefinition processDefinition : processDefinitions) {
            ReProcdef reProcdef = new ReProcdef(processDefinition);
            list.add(reProcdef);
        }
        return ToWeb.buildResult().setRows(
                ToWeb.Rows.buildRows()
                        .setRowSize(rowSize)
                        .setTotalPages((int) (count / rowSize + 1))
                        .setTotalRows(count)
                        .setList(list)
                        .setCurrent(page)
        );
    }

    /**
     * 获取所有流程
     *
     * @auther: zhaojx
     * @date: 2021/8/25 16:27
     */
    @GetMapping("list")
    public Result<List<Map<String, Object>>> list() {
        List<Map<String, Object>> list = processInfoService.process();
        return new Result<>(list);
    }

    /**
     * 获取流程节点
     *
     * @auther: zhaojx
     * @date: 2021/8/25 16:27
     */
    @GetMapping("/{proDefId}/elements")
    public Result<List<Map<String, Object>>> listActivities(@PathVariable String proDefId) {
        List<Map<String, Object>> list = new ArrayList<>();
        BpmnModel model = repositoryService.getBpmnModel(proDefId);
        if (model != null) {
            Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
            for (FlowElement e : flowElements) {
                log.info("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());
                if (e.getClass().toString().equalsIgnoreCase("class org.activiti.bpmn.model.StartEvent") ||
                        e.getClass().toString().equalsIgnoreCase("class org.activiti.bpmn.model.EndEvent") ||
                        e.getClass().toString().equalsIgnoreCase("class org.activiti.bpmn.model.UserTask")) {
                    Map<String, Object> element = new HashMap<>();
                    element.put(e.getId(), e.getName());
                    list.add(element);
                }
            }
        }
        return new Result<>(list);
    }

    /**
     * 挂起/激活流程实例
     *
     * @param key 流程定义key
     * @return
     */
    @RequestMapping(value = "suspend")
    public Object suspendAllProcessInstance(@RequestParam String key) {
        //1. 查询流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(key)
                .singleResult();

        //2.获取当前流程定义的实例是否是挂起状态
        boolean suspended = processDefinition.isSuspended();

        //3.获取流程定义的ID
        String processDefinitionId = processDefinition.getId();

        //4.如果是挂起状态则激活
        if (suspended) {
            //如果挂起则进行激活操作,第一个参数是流程定义的ID，参数二传是否激活，参数3传激活时间
            repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
            log.info("流程定义ID:{} 已经激活", processDefinitionId);
        } else {
            //5.如果是激活状态则挂起,第一个参数是流程定义的ID，参数二 是否暂停，参数3 暂停时间
            repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
            log.info("流程定义ID:{} 已经挂起", processDefinitionId);
        }
        return ToWeb.buildResult().refresh();
    }

    /**
     * 查看流程图
     * did 部署ID
     * ext 查看类型 （.bpmn / .png）
     *
     * @auther: zhaojx
     * @date: 2021/8/25 15:24
     */
//    @RequestMapping(value = "/show")
//    public void exportXmlOrImage(@RequestParam("did") String did,
//                                 @RequestParam("ext") String ext,
//                                 HttpServletResponse response) {
//        try {
//            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(did).singleResult();
//            //根据流程实例id获取流程定义
//            if (ext.equals(".png")) {
//                String resourceNmae = processDefinition.getDiagramResourceName();
//                InputStream resourceAsStream = null;
//                resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceNmae);
//                byte[] b = new byte[1024];
//                int len = -1;
//                response.setContentType("image/jpeg");
//                while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
//                    response.getOutputStream().write(b, 0, len);
//                }
//            } else if (ext.equals(".bpmn")) {//导出bpm
//                //根据processId 获取modelId
//                Model model = repositoryService.createModelQuery().deploymentId(did).singleResult();
//                String modelId = model.getId();
//                Model modelData = repositoryService.getModel(modelId);
//                BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
//                JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
//                BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
//                // 流程非空判断
//                if (!CollectionUtils.isEmpty(bpmnModel.getProcesses())) {
//                    BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
//                    byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
//
//                    ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
//                    String filename = bpmnModel.getMainProcess().getId() + ".bpmn";
//                    response.setHeader("Content-Disposition", "attachment; filename=" + filename);
//                    IOUtils.copy(in, response.getOutputStream());
//                    response.flushBuffer();
//                }
//            }
//
//        } catch (Exception e) {
//            try {
//                response.sendRedirect("process/definition/definition");
//            } catch (IOException ex) {
//                ex.printStackTrace();
//            }
//        }
//    }

    /**
     * 查看流程图
     *
     * @auther: zhaojx
     * @date: 2021/8/25 15:24
     */
    @GetMapping("show")
    public void show(@RequestParam("did") String did, @RequestParam("ext") String ext, HttpServletResponse response) throws IOException {
        if (StringUtils.isEmpty(did) || StringUtils.isEmpty(ext)) {
            return;
        }
        InputStream in = null;
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(did).singleResult();
        if (".png".equalsIgnoreCase(ext)) {
            in = repositoryService.getProcessDiagram(processDefinition.getId());
            response.setContentType("image/jpeg");
        } else if (".bpmn".equalsIgnoreCase(ext)) {
            in = repositoryService.getResourceAsStream(did, processDefinition.getResourceName());
            String fileName = processDefinition.getResourceName().replace("20.xml","");
            //指定文件下载
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName,"UTF-8"));
        }
        OutputStream out = response.getOutputStream();
        IOUtils.copy(in, out);
        response.flushBuffer();
        in.close();
        out.close();
    }


    /**
     * 删除流程实例 （注意：当有未完成的流程时无法删除该流程，如果一定要删除可以使用级联删除的方式进行删除）
     *
     * @param id 标识
     * @return
     */
    @DeleteMapping("{id}")
    public Object deleteOne(@PathVariable("id") String id) {
        //根据deploymentID删除定义的流程，普通删除
        repositoryService.deleteDeployment(id, true);
        System.out.println("普通删除--流程定义删除成功");
        return ToWeb.buildResult().refresh();
        //级联删除
//        repositoryService.deleteDeployment(id, true);
//        System.out.println("强制删除--流程定义删除成功");
    }


}
